package com.aspirecn.gateway.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.zuul.filters.RefreshableRouteLocator;
import org.springframework.cloud.netflix.zuul.filters.SimpleRouteLocator;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties.ZuulRoute;
import org.springframework.util.StringUtils;

import com.aspirecn.gateway.domain.GatewayApi;
import com.aspirecn.gateway.repository.GatewayApiRepository;

import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;


/**
 * @author chenyuanli
 */
public class ApplicationRouteLocator extends SimpleRouteLocator implements RefreshableRouteLocator{

	public final static Logger LOG = LoggerFactory.getLogger(ApplicationRouteLocator.class);

    private ZuulProperties properties;

    @Autowired
    private GatewayApiRepository gatewayApiRepository;
    
    public ApplicationRouteLocator(String servletPath, ZuulProperties properties) {
        super(servletPath, properties);
        this.properties = properties;
    }

    @Override
    public void refresh() {
        doRefresh();
    }

    @Override
    protected Map<String, ZuulRoute> locateRoutes() {
        LinkedHashMap<String, ZuulRoute> routesMap = new LinkedHashMap<String, ZuulRoute>();
        //load from application.properties
        routesMap.putAll(super.locateRoutes());
        //load from db
        routesMap.putAll(locateRoutesFromDB());
        //optimization
        LinkedHashMap<String, ZuulRoute> values = new LinkedHashMap<>();
        for (Map.Entry<String, ZuulRoute> entry : routesMap.entrySet()) {
            String path = entry.getKey();
            // Prepend with slash if not already present.
            if (!path.startsWith("/")) {
                path = "/" + path;
            }
            if (StringUtils.hasText(this.properties.getPrefix())) {
                path = this.properties.getPrefix() + path;
                if (!path.startsWith("/")) {
                    path = "/" + path;
                }
            }
            values.put(path, entry.getValue());
        }
        return values;
    }

    private Map<String, ZuulRoute> locateRoutesFromDB() {
        Map<String, ZuulRoute> routes = new LinkedHashMap<>();
        List<GatewayApi> results = gatewayApiRepository.findByEnabled(true);
        for (GatewayApi result : results) {
            if(StringUtils.isEmpty(result.getPath()) || StringUtils.isEmpty(result.getServiceId())) {
                continue;
            }
            
            ZuulRoute zuulRoute = new ZuulRoute();
            
            try {
                BeanUtils.copyProperties(result,zuulRoute);
                //必须设置否则无法传递header
                zuulRoute.setSensitiveHeaders(new LinkedHashSet<String>());
            } catch (Exception e) {
            	LOG.error("load zuul route info from db with error",e);
            }
            
            routes.put(zuulRoute.getPath(),zuulRoute);
        }
        return routes;
    }
}
